package com.scs.application.modules.base.util;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.annotation.MarkParameter;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrStockWarehouse;
import com.scs.application.modules.base.service.DeptService;
import com.scs.application.modules.base.service.MatrStockWarehouseService;
import com.scs.application.modules.dept.entity.ApplyItem;
import com.scs.application.modules.dept.entity.Demand;
import com.scs.application.modules.dept.entity.DeptReturn;
import com.scs.application.modules.dept.entity.DeptReturnItem;
import com.scs.application.modules.dept.service.ApplyItemService;
import com.scs.application.modules.dept.service.DemandItemService;
import com.scs.application.modules.dept.service.DemandService;
import com.scs.application.modules.dept.service.impl.ApplyAutoServiceImpl;
import com.scs.application.modules.msg.dto.PushDTO;
import com.scs.application.modules.msg.service.PushService;
import com.scs.application.modules.price.dto.AdjustStockDTO;
import com.scs.application.modules.price.entity.Adjustment;
import com.scs.application.modules.price.entity.AdjustmentItem;
import com.scs.application.modules.price.service.AdjustmentItemService;
import com.scs.application.modules.price.service.AdjustmentService;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.entity.OrderItem;
import com.scs.application.modules.purchase.service.OrderItemService;
import com.scs.application.modules.purchase.service.OrderService;
import com.scs.application.modules.report.entity.Config;
import com.scs.application.modules.report.entity.GridField;
import com.scs.application.modules.report.handler.BeforeReport;
import com.scs.application.modules.report.service.ConfigService;
import com.scs.application.modules.report.service.GridFieldService;
import com.scs.application.modules.sys.adapter.DataViewAdapter;
import com.scs.application.modules.sys.adapter.DictAdapter;
import com.scs.application.modules.sys.adapter.FlowAdapter;
import com.scs.application.modules.sys.adapter.SerialRuleAdapter;
import com.scs.application.modules.sys.dto.FlowDTO;
import com.scs.application.modules.sys.entity.DataView;
import com.scs.application.modules.sys.entity.SerialOwner;
import com.scs.application.modules.sys.properties.SystemProperties;
import com.scs.application.modules.sys.service.DataViewService;
import com.scs.application.modules.sys.service.SerialOwnerService;
import com.scs.application.modules.sys.service.impl.TableDataViewServiceImpl;
import com.scs.application.modules.thirdparty.service.TcbStockService;
import com.scs.application.modules.upgrade.db.enums.EntityIndexType;
import com.scs.application.modules.upgrade.db.util.MySqlSysHelper;
import com.scs.application.modules.wm.dto.PickDTO;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.service.*;
import com.scs.application.modules.wm.service.impl.DistServiceImpl;
import com.scs.application.modules.wm.service.impl.TransferServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @ Description： 公共服务方法
 */
@Slf4j
@Component
public class CommonService {
    private static final Logger logger = LoggerFactory.getLogger(CommonService.class);
    @Autowired
    private PushService pushService;
    @Autowired
    private TcbStockService tcbStockService;
    @Autowired
    StockService stockService;

    @Autowired
    private AdjustmentService adjustmentService;

    @Autowired
    private AdjustmentItemService adjustmentItemService;

    @Autowired
    private SerialRuleAdapter serialRuleAdapter;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private SystemProperties systemProperties;

    @Autowired
    private ApplyItemService applyItemService;
    @Autowired
    private  ApplyAutoServiceImpl applyAutoService;
    @Autowired
    private TransferServiceImpl transferService;
    @Autowired
    private DistServiceImpl distService;
    @Autowired
    private DistItemService distItemService;
    @Autowired
    private DemandService demandService;
    @Autowired
    private DemandItemService demandItemService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private WorkOrderItemService workOrderItemService;
    @Autowired
    private WorkOrderService workOrderService;

    @Autowired
    private FlowAdapter flowAdapter;

    private DataViewService dataViewService;

    @Autowired
    private ConfigService configService;
    @Autowired
    private GridFieldService gridFieldService;
    @Autowired
    private MatrStockWarehouseService matrStockWarehouseService;

    @Autowired
    StockLockService stockLockService;
    @Autowired
    DeptService deptService;

    @Autowired
    private SerialOwnerService serialOwnerService;

    private static CommonService services;

    @Autowired
    private DictAdapter dictAdapter;

    @Autowired
    private DataViewAdapter dataViewAdapter;

    @Autowired
    private TableDataViewServiceImpl tableDataViewServiceImpl2;

    public static int invokeTimes = 0;

    @PostConstruct
    public void init() {
        services = this;
        services.pushService = this.pushService;
        services.tcbStockService = this.tcbStockService;
        services.stockService = this.stockService;
        services.jdbcTemplate = this.jdbcTemplate;
        services.adjustmentService = this.adjustmentService;
        services.adjustmentItemService = this.adjustmentItemService;
        services.serialRuleAdapter = this.serialRuleAdapter;
        services.applyItemService = this.applyItemService;
        services.applyAutoService = this.applyAutoService;
        services.transferService = this.transferService;
        services.distService = this.distService;
        services.demandService = this.demandService;
        services.demandItemService = this.demandItemService;
        services.orderService = this.orderService;
        services.orderItemService = this.orderItemService;
        services.flowAdapter = this.flowAdapter;
        services.dataViewAdapter = this.dataViewAdapter;
        services.dictAdapter = this.dictAdapter;
        services.dataViewService = this.dataViewAdapter.getDataViewService();
        services.configService = this.configService;
        services.gridFieldService = this.gridFieldService;
        services.matrStockWarehouseService = this.matrStockWarehouseService;
        services.stockLockService = this.stockLockService;
        services.deptService = this.deptService;
        services.systemProperties = this.systemProperties;
        services.serialOwnerService = this.serialOwnerService;
        services.tableDataViewServiceImpl2 = this.tableDataViewServiceImpl2;
    }

    /**
     * @param title     标题，超过100字符将进行截取
     * @param content   内容，超过300字符将进行截取
     * @param roleCodes 角色代码，多个,号分割
     * @Description： 向特定角色的所有用户发送站内消息
     */
    @MarkParameter(type = GlobalConsts.MarkParameterTYpe.USER_MSG,msg = "用户站内消息")
    public static void pushMessageRole(String title, String content, String roleCodes) {
        PushDTO dto = new PushDTO();
        dto.setReceiverType("role");
        dto.setReceiverCodes(roleCodes);
        dto.setContentType("news");
        dto.setTitle(UtilJavax.getStringPre(title, 100));
        dto.setContent(UtilJavax.getStringPre(content, 250));
        try {
            services.pushService.pushMessageAsync(dto);
        } catch (Exception e) {
            logger.error("pushMessageRole.error 【不重要异常】", e);
        }
    }

    /**
     * @param title     标题，超过100字符将进行截取
     * @param content   内容，超过300字符将进行截取
     * @param deptId    科室ID，多个,号分割
     * @Description： 向特定科室的所有用户发送站内消息
     */
    @MarkParameter(type = GlobalConsts.MarkParameterTYpe.USER_MSG,msg = "用户站内消息")
    public static void pushMessageDept(String title, String content, String deptId) {
        PushDTO dto = new PushDTO();
        dto.setReceiverType("dept");
        dto.setReceiverCodes(deptId);
        dto.setContentType("news");
        dto.setTitle(UtilJavax.getStringPre(title, 100));
        dto.setContent(UtilJavax.getStringPre(content, 250));
        try {
            services.pushService.pushMessage(dto);
        } catch (Exception e) {
            logger.error("pushMessageRole.error 【不重要异常】", e);
        }
    }

    /**
     * @param title     标题，超过100字符将进行截取
     * @param content   内容，超过300字符将进行截取
     * @param roleCodes 角色代码，多个,号分割
     * @Description： 向特定角色的所有用户发送站内消息, 同一refid 只会创建一次
     */
    @MarkParameter(type = GlobalConsts.MarkParameterTYpe.USER_MSG,msg = "用户站内消息")
    public static void pushMessageRole(String title, String content, String roleCodes, String refId) {
        PushDTO dto = new PushDTO();
        dto.setReceiverType("role");
        dto.setReceiverCodes(roleCodes);
        dto.setContentType("news");
        dto.setTitle(UtilJavax.getStringPre(title, 100));
        dto.setContent(UtilJavax.getStringPre(content, 250));
        dto.setRefId(refId);
        services.pushService.pushMessage(dto);
    }



    /**
     * 查询前置方法，执行前置方法，替换columnSql数据源中的  %filterSql%
     *
     * @Description：${description}
     */
    public static String reportBeforeQuerycColumnSql(Config config, Map<String, Object> param) {
        String sqlNew = config.getColumnSql();
        //有前置方法
        if (StringUtils.isNotBlank(config.getPreFunColumnSql())) {
            Map param2 = new LinkedHashMap();
            param2.putAll(param);
            try {
                sqlNew = SpringUtils.invokeMethod(BeforeReport.class, config.getPreFunColumnSql(), sqlNew, param2) + "";
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException("执行前置方法%s失败，原因:%s", config.getPreFun(), e.getMessage());
            }
        }
        //替换数据源中的  %filterSql%
        sqlNew = sqlNew.replaceAll("%filterSql%", " ");
        return sqlNew;
    }

    /**
     * @Description： 报表，获取动态列
     */
    public static List<GridField> reportGetDynamicColumns(Config config, Map<String, Object> params, List<GridField> gridFieldList, List<Map<String, Object>> data) {
        if (StringUtils.isBlank(config.getColumnSql())) throw new BusinessException("动态列，缺少参数【列sql】");
        List<Map<String, Object>> columnList = services.jdbcTemplate.queryForList(reportBeforeQuerycColumnSql(config, params));

        //序号列
        GridField gridFieldSeq = new GridField();
        gridFieldSeq.setReportId(config.getId());
        gridFieldSeq.setField("seq");
        gridFieldSeq.setLabel("#");

        gridFieldSeq.setAlign("center");
        gridFieldSeq.setSort(1);
        gridFieldSeq.setFlagShow(true);
        gridFieldSeq.setFlagDynamicColumn(false);
        gridFieldSeq.setWidth("80");
        gridFieldSeq.setFixed("left");
        gridFieldList.add(0, gridFieldSeq);

        //二级表头列
        List<Map<String, Object>> columnList2 = null;
        if (StringUtils.isNotBlank(config.getColumnSql2())) {
            columnList2 = services.jdbcTemplate.queryForList(config.getColumnSql2());
        }

        if (columnList != null && columnList.size() > 0) {
            for (int i = 0; i < columnList.size(); i++) {
                Map<String, Object> column = columnList.get(i);
                //动态列，如果存在一条数据或者flag_show为1，则显示
                boolean haveHit = data.stream().anyMatch(row -> (row.get("field") + "").equalsIgnoreCase(column.get("field") + ""));
                String flag_dynamic_column = column.get("flag_dynamic_column")+"";
                if (!haveHit) continue;
                String field = column.get("field") + "";

                //二级表头列
                List<Map<String, Object>> columnList2Filter=null;
                if (columnList2 != null && columnList2.size() > 0) {
                    //动态列，如果某一月任一分组条件存在数据，则显示
                    for (int j = 0; j < columnList2.size(); j++) {
                        if (j != 0 && haveHit) break;
                        Map<String, Object> column2 = columnList2.get(j);
                        haveHit = data.stream().anyMatch(row -> (row.get("field") + "").equalsIgnoreCase(column.get("field") + "") && (row.get("field2") + "").equalsIgnoreCase(column2.get("field") + ""));
                    }
                    if (!haveHit && !"0".equalsIgnoreCase(flag_dynamic_column)) continue;

                    columnList2Filter = columnList2.stream().filter(column2 ->column2.get("field1") == null || (field.equalsIgnoreCase((String)column2.get("field1")))).collect(Collectors.toList());
                    if (columnList2Filter != null && columnList2Filter.size() > 0) {
                        for (int j = 0; j < columnList2Filter.size(); j++) {
                            Map<String, Object> column2 = columnList2Filter.get(j);
                            GridField gridField2 = new GridField();
                            gridField2.setReportId(config.getId());
                            gridField2.setField(field + column2.get("field") + "");
                            gridField2.setGroupField(field);
                            gridField2.setGroupValue((String) column2.get("field"));
                            gridField2.setLabel(column2.get("label") + "");
                            gridField2.setAlign("center");
                            gridField2.setSort(100);
                            gridField2.setFlagShow(true);
                            gridField2.setFlagDynamicColumn(true);
                            gridField2.setWidth("150").setFlagFootSum(true);
                            gridField2.setFlagNorint(false).setFlagShow(true);
                            gridField2.setFlagGroup(true).setFlagSortDisabled(true);

                            //需要隐藏全部是空的字段
                            if (config.getFlagHideNull()  ){
                                boolean haveData = data.stream().anyMatch(row -> (row.get("field2") + "").equalsIgnoreCase(column2.get("field") + ""));
                                if (!haveData) continue;

                            }
                            gridFieldList.add(gridField2);
                        }
                    };

                    //需要隐藏全部是空的字段,没有任何二级表头的情况
                    if (config.getFlagHideNull() && (columnList2Filter ==null || columnList2Filter.size() < 1) ) continue;
                }

                GridField gridField = new GridField();
                gridField.setReportId(config.getId());
                gridField.setField(field);
                gridField.setLabel(column.get("label") + "");

                gridField.setAlign("center");
                gridField.setSort(100);
                gridField.setFlagShow(true).setFlagSortDisabled(true);
                if ("0".equalsIgnoreCase(flag_dynamic_column)) {
                    gridField.setFlagDynamicColumn(false);
                }else {
                    gridField.setFlagDynamicColumn(true);
                }

                gridField.setFlagNorint(false).setFlagShow(true);
                gridField.setWidth("150");

                gridFieldList.add(gridField);

                if (config.getFlagColumnSum()  != null && config.getFlagColumnSum()  && columnList2Filter != null && columnList2Filter.size() > 0) {
                    //动态列右侧的合计
                    GridField gridField2 = new GridField();
                    gridField2.setReportId(config.getId());
                    gridField2.setField(field +"sumRight");
                    gridField2.setGroupField(field);
                    gridField2.setLabel("合计");
                    gridField2.setAlign("center");
                    gridField2.setSort(100);
                    gridField2.setFlagShow(true);
                    gridField2.setFlagDynamicColumn(true);
                    gridField2.setWidth("150").setFlagFootSum(true);
                    gridField2.setFlagGroup(true).setFlagColumnSum(true).setFlagNorint(false).setFlagShow(true).setFlagSortDisabled(true);
                    gridFieldList.add(gridField2);
                }

            }

            //最右侧合计列
            if (config.getFlagRightSum()  == null || !config.getFlagRightSum()) {
                GridField gridField = new GridField();
                gridField.setReportId(config.getId());
                gridField.setField("sumRight");
                gridField.setLabel("合计");
                gridField.setAlign("center");
                gridField.setSort(100);
                gridField.setFlagShow(true);
                gridField.setFlagDynamicColumn(false);
                gridField.setWidth("150");
                gridField.setAlign("center");
                gridField.setFixed("right").setFlagFootSum(true);
                gridField.setFlagNorint(false).setFlagShow(true).setFlagSortDisabled(true);
                gridFieldList.add(gridField);
            }
        }

        return gridFieldList;
    }

    /**
     * @Description： 报表，固定列展现二级表头 增加合计列
     */
    public static List<GridField> reportFixColumnParents(Config config, List<GridField> gridFieldList) {

        //序号列
        GridField gridFieldSeq = new GridField();
        gridFieldSeq.setReportId(config.getId());
        gridFieldSeq.setField("seq");
        gridFieldSeq.setLabel("#");

        gridFieldSeq.setAlign("center");
        gridFieldSeq.setSort(1);
        gridFieldSeq.setFlagShow(true);
        gridFieldSeq.setFlagDynamicColumn(false);
        gridFieldSeq.setWidth("80");
        gridFieldSeq.setFixed("left");
        if (!gridFieldList.contains(gridFieldSeq)){
            gridFieldList.add(0, gridFieldSeq);
        }

        List<GridField> parentFieldList = gridFieldList.stream()
                .filter(gridField -> StringUtils.isNotBlank(gridField.getParentField())).collect(Collectors.toList());
        Map<String, List<GridField>> parentFieldMap = parentFieldList.stream().collect(
                Collectors.groupingBy(GridField::getParentField));
        for (String parentField : parentFieldMap.keySet()) {
            //右侧的合计
            GridField gridField2 = new GridField();
            gridField2.setReportId(config.getId());
            gridField2.setField(parentField +"sumRight");
            gridField2.setGroupField(parentField);
            gridField2.setLabel("合计金额");
            gridField2.setAlign("center");
            gridField2.setSort(100);
            gridField2.setFlagShow(true);
            gridField2.setFlagDynamicColumn(true);
            gridField2.setWidth("150").setFlagFootSum(true);
            gridField2.setFlagGroup(true).setFlagColumnSum(true).setFlagNorint(false).setFlagShow(true).setFlagSortDisabled(true);
            if (gridFieldList.contains(gridField2)){
                continue;
            }
            gridFieldList.add(gridField2);
        }
        return gridFieldList;
    }
    /**
     * @Description： 报表，获取固定列
     */
    public static List<Map<String, Object>> reportFixColumnParentData (Config config, List<GridField> gridFieldList, Map<String, Object> params, List<Map<String, Object>> data) {
        if (data == null || data.size() < 1) return data;
        //根据主键列去重
        List<Map<String, Object>> dataUnique = data;
        List<GridField> parentFieldList = gridFieldList.stream()
                .filter(gridField -> StringUtils.isNotBlank(gridField.getParentField())).collect(Collectors.toList());
        Map<String, List<GridField>> parentFieldMap = parentFieldList.stream().collect(
                Collectors.groupingBy(GridField::getParentField));
        //追加动态列数据
        Map<String, Object> row = null;
        for (int index = 0; index < dataUnique.size(); index++) {
            row = dataUnique.get(index);
            final double[] amountSumRight = {0};
            //二级表头列
            Map<String, Object> finalRow = row;
            for (String s : parentFieldMap.keySet()) {
                double amountSum = 0;
                List<GridField> gridFields = parentFieldMap.get(s);
                for (GridField gridField : gridFields) {
                    amountSum+=UtilNum.getDouble(row.get(gridField.getField()));
                }
                dataUnique.get(index).put(s+"sumRight", amountSum);
            }
            //序号
            dataUnique.get(index).put("seq", (index + 1));
        }

        return dataUnique;
    }


    /**
     * @Description：字段去重
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * @Description： 报表，获取动态列数据
     */
    public static List<Map<String, Object>> reportGetDynamicData(Config config, List<GridField> gridFieldList, Map<String, Object> params, List<Map<String, Object>> data) {
        if (data == null || data.size() < 1) return data;
        //根据主键列去重
        List<Map<String, Object>> dataUnique = data.stream().filter(distinctByKey(row -> row.get("pk"))).collect(Collectors.toList());

        List<GridField> gridFieldGroupList = gridFieldList.stream().filter(field -> field.getFlagGroup() != null && field.getFlagGroup()).collect(Collectors.toList());
        List<GridField> gridFieldColumnList = gridFieldList.stream().filter(field -> field.getFlagColumnSum() != null && field.getFlagColumnSum()).collect(Collectors.toList());

        //追加动态列数据
        Map<String, Object> row = null;
        for (int index = 0; index < dataUnique.size(); index++) {
            row = dataUnique.get(index);
            final double[] amountSumRight = {0};
            //二级表头列
            Map<String, Object> finalRow = row;
            if (gridFieldGroupList != null && gridFieldGroupList.size() > 0) {
                for (int index2 = 0; index2 < gridFieldGroupList.size(); index2++) {
                    GridField gridField = gridFieldGroupList.get(index2);
                    //同一个主键，同一列、同一个分组条件的数据
                    List<Map<String, Object>> dataHit = data.stream().filter(
                            rowData -> (rowData.get("pk") + "").equals(finalRow.get("pk") + "")
                                    && (String.valueOf(rowData.get("field"))).equals(gridField.getGroupField())
                                    && (String.valueOf(rowData.get("field2"))).equals(gridField.getGroupValue())
                    ).collect(Collectors.toList());

                    double amountSum = 0;
                    if (dataHit != null && dataHit.size() > 0) {
                        amountSum = dataHit.stream().mapToDouble(hit -> UtilNum.getDouble(hit.get("amount"))).sum();
                    }
                    dataUnique.get(index).put(gridField.getField(), amountSum);
                    amountSumRight[0] += amountSum;
                }
            } else {
                for (int index2 = 0; index2 < gridFieldList.size(); index2++) {
                    GridField gridField = gridFieldList.get(index2);
                    if (gridField.getFlagDynamicColumn() == null || !gridField.getFlagDynamicColumn()) continue;
                    //同一个主键，同一列的数据
                    List<Map<String, Object>> dataHit = data.stream().filter(
                            rowData -> (rowData.get("pk") + "").equalsIgnoreCase(finalRow.get("pk") + "")
                                    && (rowData.get("field") + "").equalsIgnoreCase(gridField.getField())
                    ).collect(Collectors.toList());
                    double amountSum = 0;
                    if (dataHit != null && dataHit.size() > 0) {
                        amountSum = dataHit.stream().mapToDouble(hit -> UtilNum.getDouble(hit.get("amount"))).sum();
                    }
                    dataUnique.get(index).put(gridField.getField(), amountSum);
                    amountSumRight[0] += amountSum;
                }
            }

            if (gridFieldColumnList != null && gridFieldColumnList.size() > 0){
                for (int index2 = 0; index2 < gridFieldColumnList.size(); index2++) {
                    GridField gridField = gridFieldColumnList.get(index2);
                    //同一个主键，同一列、同一个分组条件的数据
                    List<Map<String, Object>> dataHit = data.stream().filter(
                            rowData -> (rowData.get("pk") + "").equals(finalRow.get("pk") + "")
                                    && (String.valueOf(rowData.get("field"))).equals(gridField.getGroupField())
                    ).collect(Collectors.toList());

                    double amountSum = 0;
                    if (dataHit != null && dataHit.size() > 0) {
                        amountSum = dataHit.stream().mapToDouble(hit -> UtilNum.getDouble(hit.get("amount"))).sum();
                    }
                    dataUnique.get(index).put(gridField.getField(), amountSum);
                    amountSumRight[0] += amountSum;
                }
            }

            //序号
            dataUnique.get(index).put("seq", (index + 1));
            //右侧合计
            dataUnique.get(index).put("sumRight", amountSumRight[0]);
        }

        return dataUnique;
    }

    /**
     * @param matrNew      新价格
     * @param stockMatr    旧价格
     * @param opUser       操作人
     * @param remark       备注
     * @param flagEnd      单据状态
     * @param stockFlagEnd 是否修改库存
     * @param adjustType   条件类型
     */
    synchronized public static Adjustment priceChange(Matr matrNew, AdjustStockDTO stockMatr, String opUser, String remark, boolean flagEnd,
                                                boolean stockFlagEnd, String adjustType) {


        // 生成调价单
        Adjustment adjustment = new Adjustment();
        adjustment.setAdjustDate(new Date())
                .setAdjustType(adjustType)
                .setAdjustKey(services.serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.ADJUST_KEY)).setRemark(remark)
                .setAdjustUser(opUser).setFlowStatus(flagEnd ? "end" : "start");
        services.adjustmentService.save(adjustment);


        AdjustmentItem adjustmentItem = new AdjustmentItem();
        BeanUtils.copyProperties(stockMatr, adjustmentItem);
        adjustmentItem.setId(null);
        adjustmentItem.setAdjustId(adjustment.getId()).setMatrId(stockMatr.getMatrId())
                .setMatrName(stockMatr.getMatrName())
                .setMatrSpec(stockMatr.getMatrSpec()).setSupplierId(stockMatr.getSupplierId())
                .setSupplierName(stockMatr.getSupplierName())
                .setFlagStock(stockFlagEnd).setSkuPriceBefore(stockMatr.getSkuPrice()).setSkuPriceAfter(matrNew.getSkuPrice())
                .setSkuPriceChange(stockMatr.getSkuPrice() - matrNew.getSkuPrice()).setHisPriceChange(0D)
                .setHrpCodeBefore(matrNew.getHrpCode()).setHrpCodeAfter(matrNew.getHrpCode()).setRemark(remark).setFlagMatr(true)
                .setFlagOmoc(stockMatr.getFlagOmoc());
        services.adjustmentItemService.save(adjustmentItem);

        if (flagEnd) services.adjustmentService.ChargeChange(adjustment);

        //推送消息给运营管理员 和管理员
        CommonService.pushMessageRole("耗材价格变动，调价单：" + adjustment.getAdjustKey(), "说明：" + remark, "admin_yy,admin");
        return adjustment;

    }


    /**
     * 请领配送： 使用配送单状态，请领调拨：使用调拨单状态，请领需求：使用采购、入库单、调拨或者配送状态 需求作废状态
     *
     * @param applyItemId 请领明细id
     * @param isClose     是否已作废
     * @Description： 更新请领需求明细状态，applyItemId为空不作处理
     */
    @Deprecated
    public static void updateApplyItemStatus(String applyItemId, boolean isClose, String remark) {
        if (StringUtils.isBlank(applyItemId)) return;
        ApplyItem applyItem = services.applyItemService.getById(applyItemId);
        if (isClose) {
            if (StringUtils.isBlank(remark)) remark = "已作废";
            if (applyItem == null) return;
            String responseStatusText = applyItem.getResponseStatusText();
            responseStatusText = UtilCommon.getStr(responseStatusText, "");
            List<DistItem> distItemList = services.distItemService.list(Wrappers.<DistItem>query().eq("apply_item_id", applyItemId));
            double pickedSkuQty = distItemList.stream().mapToDouble(DistItem::getPickedSkuQty).sum();
            UpdateWrapper updateWrapper = Wrappers.<ApplyItem>update().eq("id", applyItemId)
                    .set("response_status", "close")
                    .set("is_close", true)
                    .set("response_status_text", UserUtils.currentUser().getName() + "--作废原因 :" + remark + "。" + responseStatusText)
                    .set("response_sku_qty", pickedSkuQty);
            ;
            services.applyItemService.update(updateWrapper);
            int close = services.applyItemService.count(Wrappers.<ApplyItem>query().eq("apply_id", applyItem.getApplyId()).eq("is_close", false));
//            如果 明细全部作废， 主单据也作废
            if (close==0){
                services.jdbcTemplate.execute("UPDATE dept_apply SET is_close = 1,flow_status ='close' WHERE id =  " + applyItem.getApplyId());
            }
            return;
        }
        if (applyItem == null || StringUtils.isBlank(applyItem.getApplyType())) return;

        String responseStatus = "no";
        StringBuilder responseStatusText = new StringBuilder("未响应");
        double responseSkuQty = 0;
        switch (applyItem.getApplyType()) {
            case "1": //请领
                List<DistItem> distItemList = services.distItemService.list(Wrappers.<DistItem>query().eq("apply_item_id", applyItem.getId()));
                //有配送需求的
                if (distItemList != null && distItemList.size() > 0) {
                    responseStatus = "";
                    responseStatusText = new StringBuilder();
                    List<String> distIdList = distItemList.stream().map(DistItem::getDistId).distinct().collect(Collectors.toList());
                    double pickedSkuQty = distItemList.stream().mapToDouble(DistItem::getPickedSkuQty).sum();
                    responseSkuQty = pickedSkuQty;
                    List<Dist> distList = services.distService.list(Wrappers.<Dist>query().in("id", distIdList).orderByAsc("gmt_create"));

                    for (int i = 0; i < distList.size(); i++) {
                        String statusText = "配送完成";
                        FlowDTO flowDTO = null;
                        if (!"end".equals(distList.get(i).getFlowStatus()))
                            flowDTO = services.flowAdapter.getFlowService().getFlowDTOByCode("wm_dist");
                        if (flowDTO == null) {
                            continue;
                        }
                        statusText = services.flowAdapter.getFlowNodeService().getByFlowIdAndValue(flowDTO.getId(), distList.get(i).getFlowStatus()).getName();
                        responseStatusText.append(statusText).append("，第").append(i + 1).append("次，单号:").append(distList.get(i).getBusKey()).append("。");
                    }

                    //最后一条配送单的状态
                    List<Dist> distListNotEnd = distList.stream().filter(dist -> !dist.getFlowStatus().equals("end") && !dist.getFlowStatus().equals("dept_receiver") && !dist.getFlowStatus().equals("confirm")).collect(Collectors.toList());

                    //有一条配送单未完成，或者全部完成，但是配送数量小于需求数量
                    if (pickedSkuQty < applyItem.getSkuQty() || (distListNotEnd != null && distListNotEnd.size() > 0)) {
                        responseStatus = "distributing";
                    } else {
                        responseStatus = "end";
                    }
                }

                break;
            case "2": //需求

                //查找需求计划
                Demand demand = services.demandService.getOne(Wrappers.<Demand>query().eq("ref_id", applyItem.getApplyId()), false);
                if (demand != null) {
                    //查找采购订单
                    List<Order> orders = services.orderService.list(Wrappers.<Order>query().eq("ref_id", demand.getId()));
                    if (orders != null && !orders.isEmpty()) {
                        for (Order order : orders) {
                            if (order != null) {
                                OrderItem serviceOne = services.orderItemService.getOne(Wrappers.<OrderItem>query().eq("order_id", order.getId())
                                        .eq("apply_item_id", applyItemId), false);
                                if (serviceOne == null) continue;
                                //使用采购订单的状态
                                switch (order.getFlowStatus()) {
                                    case "end": //已审核的订单
                                        responseStatus = order.getStatusIn();
                                        switch (order.getStatusIn()) {
                                            case "0":
                                                responseStatusText = new StringBuilder("采购订单未入库");
                                                break;
                                            case "1":
                                                responseStatusText = new StringBuilder("采购订单部分入库");
                                                break;
                                            case "2":
                                                responseStatusText = new StringBuilder("采购订单全部入库");
                                                break;
                                        }
                                        responseStatus = "order_start_in_" + order.getStatusIn();
                                        break;
                                    default:
                                        //使用采购订单流程状态
                                        responseStatusText = new StringBuilder("采购订单审核中");
                                        responseStatus = "order_audit";
                                        break;
                                }
                                //订单已关闭
                                if (order.getFlagClosed() != null && order.getFlagClosed()) {
                                    responseStatusText = new StringBuilder("采购订单已关闭");
                                    responseStatusText.append(order.getClosedReason());
                                    responseStatus = "close";
                                }
                                responseStatusText.append("，单号:").append(order.getBusKey());

                                //已入库数量
                                List<OrderItem> orderItemList = services.orderItemService.list(Wrappers.<OrderItem>query().eq("order_id", order.getId()).eq("apply_item_id", applyItem.getId()));
                                if (orderItemList != null && !orderItemList.isEmpty()) {
                                    List<String> orderItemIdList = orderItemList.stream().map(OrderItem::getId).distinct().collect(Collectors.toList());
                                    List<WorkOrderItem> workOrderItemList = services.workOrderItemService.list(Wrappers.<WorkOrderItem>query().in("po_item_id", orderItemIdList));
                                    if (workOrderItemList != null) {
                                        responseSkuQty = workOrderItemList.stream().mapToDouble(WorkOrderItem::getSkuQty).sum();
                                    }

                                }

                            } else {
                                //使用需求计划的流程状态
                                responseStatusText = new StringBuilder("需求计划审核中，单号：" + demand.getBusKey());
                                responseStatus = "demand_audit";
                            }
                        }

                    }
                }
                break;
        }
        UpdateWrapper updateWrapper = Wrappers.<ApplyItem>update().eq("id", applyItemId)
                .set("response_status", responseStatus)
                .set("response_status_text", responseStatusText.toString())
                .set("response_sku_qty", responseSkuQty);
        ;
        services.applyItemService.update(updateWrapper);
    }


    /**
     * @param viewKeyOne 存在则刷新该视图，不存在刷新所有
     * @Description： 刷新dataview缓存
     */
    public static void cacheDataview(String viewKeyOne) {
        logger.info("#########CommonService.cacheDataview缓存开始#########");
        int num = 1;
        if (StringUtils.isNotBlank(viewKeyOne)) {
            DataView dataView = services.tableDataViewServiceImpl2.getOne(Wrappers.<DataView>query().eq("view_key",viewKeyOne));
            CacheUtils.remove(CacheUtils.DATAVIEW_CACHE, dataView.getViewKey());
            CacheUtils.put(CacheUtils.DATAVIEW_CACHE, dataView.getViewKey(), dataView.getJsonObject().toJSONString());
        } else {
            List<DataView> dataViewList = services.tableDataViewServiceImpl2.list(Wrappers.<DataView>query().select("view_key,json_object"));
            num = dataViewList.size();
            for (DataView dataView : dataViewList) {
                try {
                    CacheUtils.remove(CacheUtils.DATAVIEW_CACHE, dataView.getViewKey());
                    CacheUtils.put(CacheUtils.DATAVIEW_CACHE, dataView.getViewKey(), dataView.getJsonObject().toJSONString());
                } catch (Exception ex) {
                    log.error(ex.getMessage());
                }

            }
        }
        logger.info("#########CommonService.cacheDataview缓存结束，更新数据视图长度：{}#########", num);
    }

    /**
     * @param configId 存在则刷新该报表，不存在刷新所有
     * @Description： 刷新报表缓存
     */
    public static void cachereport(String configId) {
        logger.info("#########CommonService.cachereportGridField#########");
        List<Config> configList = new ArrayList<Config>();
        if (StringUtils.isNotBlank(configId)) {
            configList.add(services.configService.getById(configId));
        } else {
            configList = services.configService.list();
            CacheUtils.clearCache(CacheUtils.REPORt_GRID_FIELD_CACHE);
            CacheUtils.clearCache(CacheUtils.REPORt_CACHE);
        }
        if (configList != null && configList.size() > 0) {
            List<GridField> gridFieldList = null;
            for (Config config : configList) {
                gridFieldList = services.gridFieldService.list(Wrappers.<GridField>query().eq("report_id", config.getId()).orderByAsc("sort"));
                CacheUtils.remove(CacheUtils.REPORt_GRID_FIELD_CACHE, config.getId());
                CacheUtils.remove(CacheUtils.REPORt_CACHE, config.getId());

                CacheUtils.put(CacheUtils.REPORt_GRID_FIELD_CACHE, config.getId(), gridFieldList);
                CacheUtils.put(CacheUtils.REPORt_CACHE, config.getId(), config);
            }
            logger.info("#########CommonService.cachereportGridField 缓存结束，更新报表长度：{}#########", configList.size());
        }
    }

    /**
     * @Description： 更新耗材表的库存数字字段
     */
    public static void updateMatrStockNums(String matrId, String warehouseId) {
        logger.info("#########CommonService.updateMatrStockNums.begin#########");
        String sql = "  ";
        if (StringUtils.isNotBlank(matrId) && StringUtils.isNotBlank(warehouseId)) {
            MatrStockWarehouse matrStockWarehouseDb = services.matrStockWarehouseService.getOne(Wrappers.<MatrStockWarehouse>query().eq("warehouse_id", warehouseId).eq("matr_id", matrId));

            long stock_sku_qty = 0;
            try {
                stock_sku_qty = services.jdbcTemplate.queryForObject("select sum(sku_qty) as qtysum from wm_stock where  matr_id ='" + matrId + "' and warehouse_id = '" + warehouseId + "' ", Long.class);
            } catch (Exception e) {
            }
            if (stock_sku_qty <= 0) {
                if (matrStockWarehouseDb != null)
                    services.jdbcTemplate.execute("delete from base_matr_stock_warehouse where matr_id ='" + matrId + "' and warehouse_id = '" + warehouseId + "'  ");
            } else {
                long stock_lock_sku_qty = 0;
                try {
                    stock_lock_sku_qty = services.jdbcTemplate.queryForObject("select sum(qty)  as qtylocksum from wm_stock_lock  where  matr_id ='" + matrId + "' and warehouse_id = '" + warehouseId + "' ", Long.class);
                } catch (Exception e) {
                }

                if (matrStockWarehouseDb != null) {
                    UpdateWrapper updateWrapper = new UpdateWrapper();
                    updateWrapper.set("stock_sku_qty", stock_sku_qty);
                    updateWrapper.set("stock_lock_sku_qty", stock_lock_sku_qty);
                    updateWrapper.set("stock_use_sku_qty", stock_sku_qty - stock_lock_sku_qty);
                    updateWrapper.eq("warehouse_id", warehouseId);
                    updateWrapper.eq("matr_id", matrId);
                    services.matrStockWarehouseService.update(updateWrapper);
                } else {
                    sql += " insert into base_matr_stock_warehouse (warehouse_id,matr_id,stock_sku_qty,stock_lock_sku_qty,stock_use_sku_qty)  ";
                    sql += " VALUES (%s,%s,%s,%s,%s)  ";
                    services.jdbcTemplate.execute(String.format(sql, warehouseId, matrId, stock_sku_qty, stock_sku_qty, stock_sku_qty - stock_lock_sku_qty));
                }
            }
        } else {
            services.jdbcTemplate.execute("delete from base_matr_stock_warehouse");

            sql += " insert into base_matr_stock_warehouse (warehouse_id,matr_id,stock_sku_qty,stock_lock_sku_qty,stock_use_sku_qty)  ";
            sql += " select  ";
            sql += " t2.warehouse_id,t1.id as matr_id,ifnull(t2.qtysum,0) as stock_sku_qty,ifnull(t3.qtylocksum,0) as stock_lock_sku_qty,ifnull(t2.qtysum,0)-ifnull(t3.qtylocksum,0) as stock_use_sku_qty  ";
            sql += " from base_matr t1  ";
            sql += " inner join (select sum(sku_qty) as qtysum,matr_id,warehouse_id from wm_stock t1  group by matr_id,warehouse_id) t2 on t2.matr_id =t1.id   ";
            sql += " left join (select sum(qty)  as qtylocksum,matr_id,warehouse_id from wm_stock_lock group by matr_id,warehouse_id) t3 on t3.matr_id = t1.id  and t3.warehouse_id = t2.warehouse_id  ";
            services.jdbcTemplate.execute(sql);
        }
        logger.info("#########CommonService.updateMatrStockNums.end#########");
    }

    /**
     * @Description： 更新耗材表的库存数字字段
     */
    public static void  updateMatrStockNums(List<WorkOrder> workOrderList) {
        if (workOrderList == null || workOrderList.size() < 1) return;
        List<String> idList = workOrderList.stream().map(WorkOrder::getId).collect(Collectors.toList());
        List<String> warehouseIdList = workOrderList.stream().map(WorkOrder::getWarehouseId).distinct().collect(Collectors.toList());
        List<WorkOrderItem> workOrderItemList = services.workOrderItemService.list(Wrappers.<WorkOrderItem>query().in("work_order_id",idList));
        if (workOrderItemList == null || workOrderItemList.size() < 1) return;

        List<String> matrIdList = workOrderItemList.stream().map(WorkOrderItem::getMatrId).distinct().collect(Collectors.toList());

        warehouseIdList.stream().forEach(warehouseId -> {
            matrIdList.stream().forEach(matrId -> {
                updateMatrStockNums(matrId,warehouseId);
            });
        });
    }


    /**
     * @Description： 刷新dept缓存缓存
     */
    public static void cacheDept() {
        logger.info("#########CommonService.cacheDept#########");
        List<Dept> deptList = services.deptService.list();
        for (Dept dept : deptList) {
            CacheUtils.remove(CacheUtils.BASE_DEPT, dept.getId());
            CacheUtils.put(CacheUtils.BASE_DEPT, dept.getId(), dept);
        }
        logger.info("#########CommonService.cacheDept 缓存结束，更新部门长度：{}#########", deptList != null ? deptList.size() : 0);
    }

    /**
     * @Description： 刷新dept缓存缓存
     */
    public static void cacheSerialOwner() {
        logger.info("#########CommonService.cacheSerialOwner#########");
        List<SerialOwner> serialOwners = services.serialOwnerService.list();
        CacheUtils.clearCache(CacheUtils.SERIAL_OWNER);
        for (SerialOwner serialOwner : serialOwners) {
            CacheUtils.put(CacheUtils.SERIAL_OWNER, serialOwner.getRuleId(), serialOwner);
        }
        logger.info("#########CommonService.cacheSerialOwner 缓存结束，更新编号规则Owner长度：{}#########", serialOwners != null ? serialOwners.size() : 0);
    }

    /**
     * 流程修改记账单状态
     *
     * @param ids      影响的ids
     * @param flowDate 当前时间
     * @param flag     流程是否影响记账出库时间
     */
    public static void updatebillFlow(List<String> ids, LocalDateTime flowDate, boolean flag) {
        List<WorkOrder> workOrders = services.workOrderService
                .list(Wrappers.<WorkOrder>query().in("ref_id", ids));
        String flowStatus = "confirm";
        List<String> workIds = workOrders.stream().map(WorkOrder::getId)
                .distinct().collect(Collectors.toList());
        if (flag) {
            services.workOrderService.update(Wrappers.<WorkOrder>update().in("id", workIds).eq("flow_status", "end")
                    .set("flow_modifier", UserUtils.currentUser().getName())
                    .set("flow_modifier_code", UserUtils.currentUser().getCode())
                    .set("bus_date", flowDate)
                    .set("flow_modified", flowDate)
                    .set("flow_status", flowStatus));
            /*暂时注释掉，待后期改造wyt20211208 services.billService.update(Wrappers.<Bill>update().in("ref_id", workIds).eq("flow_status", "end")
                    .set("flow_modifier", UserUtils.currentUser().getName())
                    .set("flow_modifier_code", UserUtils.currentUser().getWorkNo())
                    .set("flow_modified", flowDate)
                    .set("bus_date", flowDate)
                    .set("flow_status", flowStatus));*/

        } else {
            services.workOrderService.update(Wrappers.<WorkOrder>update().in("id", workIds).eq("flow_status", "end")
                    .set("flow_modifier", UserUtils.currentUser().getName())
                    .set("flow_modifier_code", UserUtils.currentUser().getWorkNo())
                    .set("flow_status", flowStatus));
            /*暂时注释掉，待后期改造wyt20211208 services.billService.update(Wrappers.<Bill>update().in("ref_id", workIds).eq("flow_status", "end")
                    .set("flow_modifier", UserUtils.currentUser().getName())
                    .set("flow_modifier_code", UserUtils.currentUser().getWorkNo())
                    .set("flow_status", flowStatus));*/
        }

    }


    /**
     * @Description： 刷新报表临时表
     */
    public static void reportTempTable(Config configParam, boolean throwE) throws BusinessException {
        logger.info("#########CommonService.reportTempTable#########");
        List<Config> configList = new ArrayList<Config>();
        if (configParam != null) {
            configList.add(configParam);
        } else {
            configList = services.configService.list(Wrappers.<Config>query().eq("flag_tmptable", 1));
        }

        if (configList != null && configList.size() > 0) {
            String tempTableName, sql, fieldName;

            try {
                for (Config config : configList) {
                    synchronized (config) {
                        //创建临时表，如果不存在或者字段发生了变化
                        tempTableName = "report_temp_" + config.getCode();
                        sql = "SELECT count(1) FROM information_schema.TABLES WHERE table_schema=(select database()) and table_type = 'BASE TABLE' AND table_name = '" + tempTableName + "'";
                        long find = services.jdbcTemplate.queryForObject(sql, Long.class);

                        //临时表存在时，检查临时表字段是否发生了变化
                        boolean tableCHange = false;
                        if (find > 0) {
                            Map mapSource = null, mapTempTable = null;
                            try {
                                mapSource = services.jdbcTemplate.queryForMap(" select * from (" + config.getTmptableSql() + ") t limit 1   ");
                            } catch (Exception e) {
                                if (throwE) logger.error("CommonService.reportTempTable.find.error", e);
                            }
                            try {
                                mapTempTable = services.jdbcTemplate.queryForMap(" select * from " + tempTableName + "  limit 1   ");
                            } catch (Exception e) {
                                if (throwE) logger.error("CommonService.reportTempTable.find.error", e);
                            }
                            //有数据时再进行对比
                            if (mapSource != null && mapTempTable != null) {
                                Map finalMapTempTable = mapTempTable, finalMapSource = mapSource;
                                ;

                                //临时表少字段的
                                tableCHange = mapSource.keySet().stream().anyMatch(key -> finalMapTempTable.keySet().stream().noneMatch(key2 -> key2.equals(key)));

                                //临时表多字段的
                                if (!tableCHange)
                                    tableCHange = mapTempTable.keySet().stream().anyMatch(key -> finalMapSource.keySet().stream().noneMatch(key2 -> key2.equals(key)));
                            }
                            //表结构变化或者临时表没数据的，直接删除掉就可以
                            if (tableCHange || mapTempTable == null) {
//                                更新打印时间时备份打印时间字段
                                if (config.getFlagPrint()) {
                                    String sqlBak = "SELECT count(1) FROM information_schema.TABLES " +
                                            "WHERE table_schema=(select database()) and table_type = 'BASE TABLE' AND table_name = '" + tempTableName + "_print" + "'";
                                    long count = services.jdbcTemplate.queryForObject(sqlBak, Long.class);
                                    if (count > 0) {
                                        services.jdbcTemplate.execute("drop table " + tempTableName + "_print");
                                    }
                                    services.jdbcTemplate.execute("CREATE TABLE " + tempTableName + "_print" + " as SELECT " + config.getTmptableFieldPks()
                                            + ", print_time,flag_print FROM  " + tempTableName);
                                    MySqlSysHelper.addIndex(services.jdbcTemplate, tempTableName + "_print", EntityIndexType.PRIMARY, "pri", config.getTmptableFieldPks());

                                }
                                tableCHange = true;
                                services.jdbcTemplate.execute("drop table " + tempTableName);

                            }
                        }

                        if (find < 1 || tableCHange) {
                            sql = "";
                            sql += " create table " + tempTableName + "  ";
                            sql += " as   ";
                            sql += " select * from (" + config.getTmptableSql() + ") t where 1=0   ";
                            services.jdbcTemplate.execute(sql);

                            //主键索引
                            if (StringUtils.isNotBlank(config.getTmptableFieldPks())) {
                                MySqlSysHelper.addIndex(services.jdbcTemplate, tempTableName, EntityIndexType.PRIMARY, "pri", config.getTmptableFieldPks());
                            }

                            //唯一索引
                            if (StringUtils.isNotBlank(config.getTmptableFieldUnqs())) {
                                for (String field : config.getTmptableFieldUnqs().split(",")) {
                                    MySqlSysHelper.addIndex(services.jdbcTemplate, tempTableName, EntityIndexType.UNIQUE_INDEX, "unq" + field, field);
                                }
                            }

                            //普通索引
                            if (StringUtils.isNotBlank(config.getTmptableFieldIndexs())) {
                                for (String field : config.getTmptableFieldIndexs().split(",")) {
                                    MySqlSysHelper.addIndex(services.jdbcTemplate, tempTableName, EntityIndexType.INDEX, "ind" + field, field);
                                }

                            }
                        }

                        //添加数据
                        sql = "select * from (" + config.getTmptableSql() + ") t  ";
                        String sqlCount = "select 1 as count from (" + config.getTmptableSql() + ") t  ";
                        String sqlPk = "select " + config.getTmptableFieldPks() + "  from (" + config.getTmptableSql() + ") t  ";
                        if (StringUtils.isNotBlank(config.getTmptableFieldMax())) { //根据最大值
                            String maxValue = null;
                            try {
                                maxValue = services.jdbcTemplate.queryForObject("select max(" + config.getTmptableFieldMax() + ")  from " + tempTableName + "  ", String.class);
                            } catch (Exception e) {
                            }

                            if (StringUtils.isNotBlank(maxValue)) {
                                sql += " where " + config.getTmptableFieldMax() + "> '" + maxValue + "' ";
                                sqlCount += " where " + config.getTmptableFieldMax() + "> '" + maxValue + "' ";
                                sqlPk += " where " + config.getTmptableFieldMax() + "> '" + maxValue + "' ";
                            }
                        } else if (StringUtils.isNotBlank(config.getTmptableFieldPks())) {//根据主键
                            if (config.getTmptableFieldPks().split(",").length > 1) {
                                throw new BusinessException("报表【%s】为多主键，请指定最大字段后再添加数据", config.getName());
                            }
                            sql += " where " + config.getTmptableFieldPks() + " not in ( select " + config.getTmptableFieldPks() + " from " + tempTableName + " ) ";
                            sqlCount += " where " + config.getTmptableFieldPks() + " not in ( select " + config.getTmptableFieldPks() + " from " + tempTableName + " ) ";
                        } else {
                            if (throwE) logger.error("报表【{}】缺少唯一字段和最大字段，无法添加数据", config.getName());
                            continue;
                        }

                        //

                        //有符合条件的数据再执行
                        long count = 0;
                        try {
                            sqlCount += " limit 1";
                            count = services.jdbcTemplate.queryForObject(sqlCount, Long.class);
                        } catch (Exception e) {
                            if (throwE) logger.error("CommonService.reportTempTable.find.error", e);
                        }
                        sql = " insert into " + tempTableName + " " + sql;
                        if (count > 0) {
                            //因为手动修改数据最大值，可能会导致重复添加，此处添加前进行删除，日期往后调的情况
                            if (StringUtils.isNotBlank(config.getTmptableFieldMax()) && StringUtils.isNotBlank(config.getTmptableFieldPks())) { //根据最大值
                                String sqlPkidRemove = " select t1." + config.getTmptableFieldPks() + " from ( " + sqlPk + ") t1 inner join " + tempTableName + " t2 on t1." + config.getTmptableFieldPks() + " = t2." + config.getTmptableFieldPks();

                                List<String> removePkIds = services.jdbcTemplate.queryForList(sqlPkidRemove, String.class);
                                if (removePkIds != null && removePkIds.size() > 0) {
                                    List<String> removePkIds2 = new ArrayList<String>();
                                    removePkIds.forEach(id -> removePkIds2.add("'" + id + "'"));
                                    services.jdbcTemplate.execute(" delete from " + tempTableName + " where " + config.getTmptableFieldPks() + " in (" + StringUtils.join(removePkIds2, ",") + ")");
                                }

                            }
                            services.jdbcTemplate.execute(sql);
//                            表结构变化 更新打印时间
                            if (tableCHange && config.getFlagPrint()) {
                                services.jdbcTemplate.execute(" UPDATE " + tempTableName + "  SET print_time = NULL ");
                                services.jdbcTemplate.execute(" UPDATE " + tempTableName + " t1 INNER JOIN " + tempTableName + "_print"
                                        + " t2 ON t1." + config.getTmptableFieldPks() + " = t2." + config.getTmptableFieldPks() +
                                        " SET t1.print_time = t2.print_time ,t1.flag_print =  t2.flag_print ");

                            }
                            logger.info("#########CommonService.reportTempTable、临时表数据添加结束，报表标识：{}，报表名称：{}，临时表：{}#########", config.getCode(), config.getName(), tempTableName);
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("CommonService.reportTempTable.error", e);
                if (throwE) throw new BusinessException(e.getMessage());
            }

            logger.info("#########CommonService.reportTempTable 结束，临时表长度：{}#########", configList.size());
        }
    }

    /**
     * @throws BusinessException 校验失败
     * @Description： 校验库存   单品数量*单品价格 是否等于 合计金额，校验库存效期
     */
    public static void checkStock(Stock stock, LockBusType busType) throws BusinessException {
        //单品数量*单品价格 是否等于 合计金额
        double sum = UtilNum.mul(stock.getSkuPrice(), stock.getSkuQty());
        if (Math.abs(sum) != Math.abs(stock.getAmount()))
            throw new BusinessException("库存校验失败！<br>金额【%s】不等于单品数量【%s】*单品价格【%s】，实际相乘后金额【%s】", stock.getAmount(), stock.getSkuQty(), stock.getSkuPrice(), sum);


        if (busType != null) {
            //供应商退货的时候不用校验库存
            if (busType == LockBusType.OUT_ORDER) return;
        }


        //校验效期
        if (stock.getExpDate() == null)
            throw new BusinessException("库存校验失败！<br>缺少效期，品名：【%s】，品规：【%s】，SN码：【%s】", stock.getMatrName(), stock.getMatrSpec(), stock.getSn());
        if (DateUtils.getDateDiffOfDays(DateUtils.now(), stock.getExpDate()) < 0)
            throw new BusinessException("库存校验失败！<br>已过期，品名：【%s】，品规：【%s】，SN码：【%s】，效期：【%s】",
                    stock.getMatrName(), stock.getMatrSpec(), stock.getSn(), DateUtils.format(stock.getExpDate(), "yyyy-MM-dd"));
    }

    /**
     * @throws BusinessException 校验失败
     * @Description： 科室退库校验状态
     */
    public static void checkDeptReturn(String sn, double skuQty, String deptId, DeptReturnItem deptReturnItem, DeptReturn deptReturnDb) {
        //检查目标仓库是否配送过该库存
        if (deptReturnItem != null) {
            double pickNum = 0;
            try {
                pickNum = services.jdbcTemplate.queryForObject("select count(1) from wm_pick_item t1 inner join wm_dist t2 on t1.dist_id = t2.id where t1.stock_id = '" + deptReturnItem.getStockId() + "' and t2.warehouse_id ='" + deptReturnDb.getWarehouseId() + "' and t2.dept_id ='" + deptReturnDb.getDeptId() + "'", Long.class);
            } catch (EmptyResultDataAccessException e) {
            }
            if (pickNum <= 0) {
                throw new BusinessException(String.format("目标仓库【%s】未向科室【%s】配送过该唯一码【%s】，请重新选择退货科室或者目标仓库", deptReturnDb.getWarehouseName(), deptReturnDb.getDeptName(), deptReturnItem.getSn())); }
        }


        //配送数量-科室退货数量=可以退货的数量
        double distItemSkuQtySum = 0;
        double deptItemSkuQtySum = 0;
        double outspItemSkuQtySum = 0;
        String sql = " select sum(sku_qty) from (select id from wm_work_order where bus_type='OUT_SP') t1 ";
        sql += " inner join (select work_order_id,sku_qty from wm_work_order_item where sn ='" + sn + "') t2 on t1.id = t2.work_order_id ";
        try {
            outspItemSkuQtySum = UtilNum.getDouble(services.jdbcTemplate.queryForObject(sql, String.class));
        } catch (EmptyResultDataAccessException e) {
        }

        sql = " select sum(sku_qty) from wm_pick_item t1 INNER JOIN wm_dist t2 ON t1.dist_id =t2.id   where  dept_id = '" + deptId + "' AND sn ='" + sn + "' and t2.warehouse_id='" + deptReturnDb.getWarehouseId() + "' ";
        try {
            distItemSkuQtySum = UtilNum.getDouble(services.jdbcTemplate.queryForObject(sql, String.class));
        } catch (EmptyResultDataAccessException e) {
        }
        sql = " SELECT sum(sku_qty) FROM dept_return t1 INNER JOIN dept_return_item t2 ON t1.id = t2.dept_return_id  where  dept_id = '" + deptId + "' AND sn ='" + sn + "' and t1.warehouse_id='" + deptReturnDb.getWarehouseId() + "'  ";

        //需要排除掉的退货明细id
        if (deptReturnItem != null) { sql += " and t2.id != '" + deptReturnItem.getId() + "' "; }
        try {
            deptItemSkuQtySum = UtilNum.getDouble(services.jdbcTemplate.queryForObject(sql, String.class));
        } catch (EmptyResultDataAccessException e) {
        }

        if (distItemSkuQtySum - outspItemSkuQtySum - deptItemSkuQtySum - skuQty < 0) {
            throw new BusinessException(String.format("唯一码【%s】 已配送数量【%s】-已供应商退货数量【%s】-已科室退货数量【%s】-当前退货数量【%s】已不足0,无法进行科室退货", sn, distItemSkuQtySum, outspItemSkuQtySum, deptItemSkuQtySum, skuQty));
        }
    }

    /**
     * @param tableName 业务表名称
     * @param busId     业务单据id
     * @Description： 更新业务单据的序列号字段，一般审核通过post之后调用
     */
    public static void updateBusTableSnum(String tableName, String busId) {
        synchronized (tableName) {
            logger.info("#########CommonService.updateBusTableSnum.begin#########");
            double snumCurr = 0;
            String sql = " select max(snum) from " + tableName;
            try {
                snumCurr = services.jdbcTemplate.queryForObject(sql, Long.class);
            } catch (Exception e) {
            }
            snumCurr++;
            sql = " update  %s set snum = '%s' where id ='%s'";
            services.jdbcTemplate.execute(String.format(sql, tableName, snumCurr, busId));
            logger.info("#########CommonService.updateBusTableSnum.snumCurr={}#########", snumCurr);
            logger.info("#########CommonService.updateBusTableSnum.end#########");
        }

    }




    /**
     *
     * @param idList -1: dept_auto_apply.id 集合
     *               1: purchase_order.id 集合
     * @param type -1:重置关联需求在途数量和关联单号
     *             1:更新关联需求在途数量和关联单号
     * @Description： 更新/重置在途数量和关联单号
     */
    public static void updateApplyInfo(List<String> idList, int type) {
        services.applyAutoService.updateApplyInfo(idList,type);
    }

    /**
     * @param pickDTOs 符合条件的库存信息
     * @Description： 公用批量拣货方法
     */
    public static void pickBatch(List<PickDTO> pickDTOs) {
        services.distService.pickBatch(pickDTOs);
    }

    /**
     * @param stockIds ：库存id集合
     * @param flagOmoc : 是否是一物一码
     * @Description： 非科室退库业务, 冲红校验状态
     */
    public static void checkRedStock(List<String> stockIds, Boolean flagOmoc) {
        if (CollectionUtils.isEmpty(stockIds)) {
            return;
        }
        double outspItemSkuQtySum = 0;
        try {
            outspItemSkuQtySum = services.workOrderItemService.getOutspItemSkuQtySum(stockIds, flagOmoc);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        }
        List<Stock> stocks = services.stockService.listStockWithZero(Wrappers.<Stock>query()
                .eq("flag_omoc", flagOmoc).gt("sku_qty", 0).in("id", stockIds), null);
        if (stocks != null && !stocks.isEmpty()) {
            List<String> snList = stocks.stream().map(Stock::getSn).collect(Collectors.toList());
            String sns = StringUtils.join(snList, ",");
            throw new BusinessException("当前单据,存在耗材未消耗 SN: " + sns);
        }
        if (outspItemSkuQtySum > 0) {
            throw new BusinessException("当前单据,存在耗材进行过供应商出库,无法进行整单冲红");
        }
    }

    /**
     * @throws
     * @Description： 是否业务科室校验
     */
    public static void checkDept(String deptId) {
        //非业务科室判断
        Dept dept = (Dept) CacheUtils.get(CacheUtils.BASE_DEPT, deptId);
        if (dept != null && dept.getFlagBus() != true) {
            throw new BusinessException("校验失败！<br>科室【%s】非业务科室，不可以进行业务操作", dept.getName());
        }
    }
}
